﻿using System;
using System.Collections.Generic;
using System.Windows.Threading;
using Iorz.DomainSearch.Utils.Provider;
using Iorz.DomainSearch.Utils.Worker;

namespace Iorz.DomainSearch
{
    public class Domain
    {
        private List<SearchWorker> mWorkers = new List<SearchWorker>();

        private int mCompleteCount = 0;

        private Dispatcher mOwner = null;

        private List<IProvider> mProviders = null;

        private void StartWorker(SearchWorker worker)
        {
            lock (mWorkers)
            {
                mWorkers.Add(worker);
            }

            worker.Start();
        }

        public void StopWorker()
        {
            lock (mWorkers)
            {
                foreach (var worker in mWorkers)
                {
                    worker.Discard();
                }

                for (int i = mWorkers.Count - 1; i >= 0; i--)
                {
                    var worker = mWorkers[i];
                    worker.WaitFor();
                    worker = null;
                    mWorkers.RemoveAt(i);
                }
            }
        }

        public Domain(Dispatcher owner, List<IProvider> provider)
        {
            this.mOwner = owner;
            this.mProviders = provider;
        }

        public void Search(string[] suffixs, string format, int domainLength, Action<bool, string, string> handler, Action complete)
        {
            var threadCount = mProviders.Count;

            var chars = SearchWorker.ZM_LEFT_RIGHT.ToCharArray();
            var prefixCount = (chars.Length + (chars.Length % threadCount)) / threadCount;

            for (int index = 0, i = 0; i < chars.Length; i += prefixCount, index++)
            {
                var prefixs = new List<string>();
                foreach (var item in SearchWorker.ZM_LEFT_RIGHT.Substring(i, prefixCount).ToCharArray())
                {
                    prefixs.Add(item.ToString());
                }

                var worker = new SearchWorker(mOwner, mProviders[index], prefixs.ToArray(), suffixs, format, domainLength);
                worker.OnNotifyUI = handler;
                worker.OnTerminated = new Action(() =>
                {
                    mCompleteCount++;
                    if (mCompleteCount == mWorkers.Count)
                        complete?.Invoke();
                });
                StartWorker(worker);
            }
        }

        public static double CalculateCount(string domains, string domainLength)
        {
            var count = domains.Trim().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Length;
            if (count <= 0)
                return 0;

            var length = 0;
            if (!int.TryParse(domainLength.Trim(), out length) || length <= 0)
                return 0;

            var result = 1d;
            for (int i = 0; i < length; i++)
            {
                if (i == 0 || i == length - 1) result *= SearchWorker.ZM_LEFT_RIGHT.Length;
                else result *= SearchWorker.ZM_MIDDLE.Length;
            }

            return result * count;
        }
    }
}
